#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import os
import sys

from common.cleaner import clear
from common.const import SysData
from exchange import log
from exchange.commons.common import output_action_result, read_temp_file, check_del_dir_or_file
from exchange.commons.const import ExchangeCode, BodyErr, ParamConstant, ExchangeRestoreType
from exchange.restore.exchange_database_restore.exchange_restore_database import ExchangeRestoreDatabase
from exchange.restore.restore_param_parser import RestoreParamParser


class ExchangeRestoreCommon:
    def __init__(self, pid):
        self.pid = pid
        self._exchange_object = None
        self._restore_type = ""

    @staticmethod
    def get_code(input_ret):
        if input_ret:
            return ExchangeCode.SUCCESS.value
        else:
            return ExchangeCode.FAILED.value

    @staticmethod
    def format_body_err(input_ret):
        tmp_body_err = 0
        if not input_ret:
            tmp_body_err = BodyErr.ERR_PLUGIN_CANNOT_BACKUP.value
        return tmp_body_err

    def create_restore_by_type(self, tmp_job_id, tmp_sub_job_id):
        log.info("Create_restore_by_restore, job_id is %s. sub_job_id is %s", tmp_job_id, tmp_sub_job_id)
        file_path = os.path.join(ParamConstant.PARAM_FILE_PATH, f"param{self.pid}")
        try:
            json_param = read_temp_file(file_path)
        except Exception as err:
            log.error("Read param file failed, err mgs is: %s.", str(err))
            return False
        finally:
            check_del_dir_or_file(file_path)
        self._restore_type = RestoreParamParser.get_restore_resource_sub_type(json_param)
        if self._restore_type == ExchangeRestoreType.EXCHANGE_RESTORE_DATABASE:
            self._exchange_object = ExchangeRestoreDatabase(self.pid, tmp_job_id, tmp_sub_job_id, json_param)
        else:
            log.error("Restore type is wrong: %s.", self._restore_type)
            return False
        return True

    def allow_restore_in_local_node(self):
        try:
            ret = self._exchange_object.allow_restore_in_local_node()
            if not ret:
                output_action_result(self.pid, ExchangeCode.FAILED.value, 0, "")
        except Exception as err:
            log.error("Exception during allow_restore_in_local_node: %s", str(err))
            output_action_result(self.pid, ExchangeCode.FAILED.value, BodyErr.ERROR_INTERNAL.value,
                                 f"Exception during allow_restore_in_local_node.")
            return False
        output_action_result(self.pid, ExchangeCode.SUCCESS.value, 0, "")
        return ret

    def restore_prerequisite(self):
        ret = self._exchange_object.restore_preprequisite()
        if not ret:
            log.error("restore_preprequisite failed.")
        output_action_result(self.pid, self.get_code(ret), self.format_body_err(ret), "")
        return True

    def restore_gen_sub_job(self):
        ret = self._exchange_object.restore_gen_sub_job()
        if not ret:
            log.error("restore_gen_sub_job failed.")
            output_action_result(self.pid, self.get_code(ret), self.format_body_err(ret), "")
        return True

    def restore(self):
        ret = self._exchange_object.restore()
        if not ret:
            log.error("restore failed.")
            output_action_result(self.pid, self.get_code(ret), self.format_body_err(ret), "")
        return True

    def restore_post_job(self):
        ret = self._exchange_object.restore_post_job()
        if not ret:
            log.error("restore_post_job failed.")
            output_action_result(self.pid, self.get_code(ret), self.format_body_err(ret), "")
        return True

    def query_job_permission(self):
        ret = self._exchange_object.query_job_permission()
        output_action_result(self.pid, self.get_code(ret), self.format_body_err(ret), "")
        return True

    def progress_comm(self):
        self._exchange_object.progress_comm()
        return True


def restore_main(args_list):
    cmd = args_list[0]
    pid = args_list[1]
    job_id = ""
    sub_job_id = ""
    if len(args_list) >= 3:
        job_id = args_list[2]
    if len(args_list) == 4:
        sub_job_id = args_list[3]
    restore_common_instance = ExchangeRestoreCommon(pid)
    if not restore_common_instance.create_restore_by_type(job_id, sub_job_id):
        log.error("Create instance failed.")
        output_action_result(pid, ExchangeCode.FAILED.value, BodyErr.ERROR_INTERNAL.value,
                             f"Create instance failed.")
        return False
    cmd_dict = {
        "AllowRestoreInLocalNode": [restore_common_instance.allow_restore_in_local_node],
        "RestorePrerequisite": [restore_common_instance.restore_prerequisite],
        "RestoreGenSubJob": [restore_common_instance.restore_gen_sub_job],
        "Restore": [restore_common_instance.restore],
        "RestorePostJob": [restore_common_instance.restore_post_job],
        "QueryJobPermission": [restore_common_instance.query_job_permission],
        "progress_comm": [restore_common_instance.progress_comm]
    }
    func_array = cmd_dict.get(cmd)
    if not func_array:
        log.error("No matched cmd!")
        output_action_result(pid, ExchangeCode.FAILED.value, BodyErr.ERROR_INTERNAL.value,
                             f"No matched cmd!")
        return False
    try:
        ret = func_array[0]()
    except Exception as e:
        log.error("Exception during execute job: %s.", str(e))
        output_action_result(pid, ExchangeCode.FAILED.value, BodyErr.ERROR_INTERNAL.value,
                             f"Execute job failed.")
        return False
    finally:
        clear(SysData.SYS_STDIN)
    return ret


if __name__ == "__main__":
    # 接收由框架写入到stdin中的敏感信息
    for line in sys.stdin:
        SysData.SYS_STDIN = line
        break
    args = sys.argv[1:]
    if len(args) < 2:
        log.error("No enough parameters, param cnt: %s.", len(args))
        sys.exit(1)
    if not restore_main(args):
        sys.exit(1)
    sys.exit(0)
